home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gawk
/
gawk213b.zoo
/
test
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-31
|
20KB
|
847 lines
/*
* io.c - routines for dealing with input and output and records
*/
/*
* Copyright (C) 1986, 1988, 1989, 1991 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
*
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "awk.h"
#ifndef O_RDONLY
#include <fcntl.h>
#endif
#ifndef atarist
#define INVALID_HANDLE (-1)
#else
#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1)
#endif
static IOBUF *nextfile P((void));
static int inrec P((IOBUF *iop, int getline_redirect));
static int iop_close P((IOBUF *iop));
struct redirect *redirect P((NODE *tree, int *errflg));
static void close_one P((void));
static int close_redir P((struct redirect *rp));
#if (!defined(MSDOS)) && (!defined(atarist))
static int wait_any P((int interesting));
#endif
static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
static int gawk_pclose P((struct redirect *rp));
static int do_pathopen P((char *file));
static struct redirect *red_head = NULL;
static IOBUF *curfile = NULL;
extern int output_is_tty;
extern NODE *ARGC_node;
extern NODE *ARGV_node;
extern NODE **fields_arr;
static IOBUF *
nextfile()
{
static int i = 1;
static int files = 0;
char *arg;
int fd = INVALID_HANDLE;
extern char *arg_assign();
if (curfile != NULL && curfile->cnt != EOF)
return curfile;
for (; i < (int) (ARGC_node->lnode->numbr); i++) {
arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr;
if (*arg == '\0')
continue;
if (!arg_assign(arg)) {
files++;
fd = devopen(arg, "r");
if (fd == INVALID_HANDLE)
fatal("cannot open file `%s' for reading (%s)",
arg, strerror(errno));
/* NOTREACHED */
/* This is a kludge. */
unref(FILENAME_node->var_value);
FILENAME_node->var_value =
make_string(arg, strlen(arg));
FNR = 0;
i++;
break;
}
}
if (files == 0) {
files++;
/* no args. -- use stdin */
/* FILENAME is init'ed to "-" */
/* FNR is init'ed to 0 */
fd = 0;
}
if (fd == INVALID_HANDLE)
return NULL;
return curfile = iop_alloc(fd);
}
void
set_FNR()
{
FNR = (int) FNR_node->var_value->numbr;
}
void
set_NR()
{
NR = (int) NR_node->var_value->numbr;
}
/*
* This reads in a record from the input file
*/
static int
inrec(iop, getline_redirect)
IOBUF *iop;
int getline_redirect;
{
char *begin;
register int cnt;
int retval = 0;
cnt = get_a_record(&begin, iop, *RS);
if (cnt == EOF) {
cnt = 0;
retval = 1;
} else if (!getline_redirect) {
NR += 1;
FNR += 1;
}
set_record(begin, cnt, 1);
return retval;
}
static int
iop_close(iop)
IOBUF *iop;
{
int ret;
if (iop == NULL)
return 0;
errno = 0;
/* Work around bug in UNICOS popen, but it shouldn't hurt elsewhere */
if (iop->fd < 3)
ret = 0;
else
ret = close(iop->fd);
if (ret == -1)
warning("close of fd %d failed (%s)", iop->fd, strerror(errno));
free(iop->buf);
free(iop->secbuf);
if (iop == curfile)
curfile = NULL; /* kludge -- gotta do better */
free((char *)iop);
return ret == -1 ? 1 : 0;
}
void
do_input()
{
IOBUF *iop;
extern int exiting;
while ((iop = nextfile()) != NULL) {
if (inrec(iop, 0) == 0)
while (interpret(expression_value) && inrec(iop, 0) == 0)
;
(void) iop_close(iop);
iop = NULL;
if (exiting)
break;
}
}
/* Redirection for printf and print commands */
struct redirect *
redirect(tree, errflg)
NODE *tree;
int *errflg;
{
register NODE *tmp;
register struct redirect *rp;
register char *str;
int tflag = 0;
int outflag = 0;
char *direction = "to";
char *mode;
int fd;
switch (tree->type) {
case Node_redirect_append:
tflag = RED_APPEND;
case Node_redirect_output:
outflag = (RED_FILE|RED_WRITE);
tflag |= outflag;
break;
case Node_redirect_pipe:
tflag = (RED_PIPE|RED_WRITE);
break;
case Node_redirect_pipein:
tflag = (RED_PIPE|RED_READ);
break;
case Node_redirect_input:
tflag = (RED_FILE|RED_READ);
break;
default:
fatal ("invalid tree type %d in redirect()", tree->type);
break;
}
tmp = force_string(tree_eval(tree->subnode));
str = tmp->stptr;
for (rp = red_head; rp != NULL; rp = rp->next)
if (strlen(rp->value) == tmp->stlen
&& STREQN(rp->value, str, tmp->stlen)
&& ((rp->flag & ~RED_NOBUF) == tflag
|| (outflag
&& (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
break;
if (rp == NULL) {
emalloc(rp, struct redirect *, sizeof(struct redirect),
"redirect");
emalloc(str, char *, tmp->stlen+1, "redirect");
memcpy(str, tmp->stptr, tmp->stlen);
str[tmp->stlen] = '\0';
rp->value = str;
rp->flag = tflag;
rp->offset = 0;
rp->fp = NULL;
rp->iop = NULL;
rp->pid = 0; /* unlikely that we're worried about init */
rp->status = 0;
/* maintain list in most-recently-used first order */
if (red_head)
red_head->prev = rp;
rp->prev = NULL;
rp->next = red_head;
red_head = rp;
}
while (rp->fp == NULL && rp->iop == NULL) {
mode = NULL;
errno = 0;
switch (tree->type) {
case Node_redirect_output:
mode = "w";
break;
case Node_redirect_append:
mode = "a";
break;
case Node_redirect_pipe:
if ((rp->fp = popen(str, "w")) == NULL)
fatal("can't open pipe (\"%s\") for output (%s)",
str, strerror(errno));
rp->flag |= RED_NOBUF;
break;
case Node_redirect_pipein:
direction = "from";
if (gawk_popen(str, rp) == NULL)
fatal("can't open pipe (\"%s\") for input (%s)",
str, strerror(errno));
break;
case Node_redirect_input:
direction = "from";
rp->iop = iop_alloc(devopen(str, "r"));
break;
default:
cant_happen();
}
if (mode != NULL) {
fd = devopen(str, mode);
if (fd > INVALID_HANDLE) {
if (fd == fileno(stdin))
rp->fp = stdin;
else if (fd == fileno(stdout))
rp->fp = stdout;
else if (fd == fileno(stderr))
rp->fp = stderr;
else
rp->fp = fdopen(fd, mode);
if (isatty(fd))
rp->flag |= RED_NOBUF;
}
}
if (rp->fp == NULL && rp->iop == NULL) {
/* too many files open -- close one and try again */
#ifdef atarist
if (errno == EMFILE)
#else
if (errno == ENFILE || errno == EMFILE)
#endif
close_one();
else {
/*
* Some other reason for failure.
*
* On redirection of input from a file,
* just return an error, so e.g. getline
* can return -1. For output to file,
* complain. The shell will complain on
* a bad command to a pipe.
*/
*errflg = 1;
if (tree->type == Node_redirect_output
|| tree->type == Node_redirect_append)
fatal("can't redirect %s `%s' (%s)",
direction, str, strerror(errno));
else
return NULL;
}
}
}
if (rp->offset != 0) /* this file was previously open */
if (fseek(rp->fp, rp->offset, 0) == -1)
fatal("can't seek to %ld on `%s' (%s)",
rp->offset, str, strerror(errno));
free_temp(tmp);
return rp;
}
static void
close_one()
{
register struct redirect *rp;
register struct redirect *rplast = NULL;
/* go to end of list first, to pick up least recently used entry */
for (rp = red_head; rp != NULL; rp = rp->next)
rplast = rp;
/* now work back up through the list */
for (rp = rplast; rp != NULL; rp = rp->prev)
if (rp->fp && (rp->flag & RED_FILE)) {